#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__

#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <cerrno>
#include <strings.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "Common.hpp"
#include "ThreadPool.hpp"

using namespace LogModule;
using namespace ThreadPoolModule;

const static int gsockfd = -1;
// const static std::string gdefaultip = "127.0.0.1"; // 表示本地主机
const static uint16_t gdefaultport = 8080;

using adduser_t = std::function<void(InetAddr &id)>;
using remove_t = std::function<void(InetAddr &id)>;

using task_t = std::function<void()>;
using route_t = std::function<void(int sockfd, const std::string &message)>;

class nocopy
{
public:
    nocopy(){}
    nocopy(const nocopy &) = delete;
    const nocopy& operator = (const nocopy &) = delete;
    ~nocopy(){}
};

class UdpServer : public nocopy
{
public:
    UdpServer(uint16_t port = gdefaultport)
        : _sockfd(gsockfd),
          _addr(port),
          _isrunning(false)
    {
    }
    // 都是套路
    void InitServer()
    {
        // 1. 创建socket
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); // IP?PORT?网络？本地？
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;

        // 2. 填充网络信息，并bind绑定
        // 2.1 有没有把socket信息，设置进入内核中？？没有，只是填充了结构体！
        // struct sockaddr_in local;
        // bzero(&local, sizeof(local));
        // local.sin_family = AF_INET;
        // local.sin_port = ::htons(_port);                  // 要被发送给对方的，即要发到网络中！
        // //local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 1. string ip->4bytes 2. network order //TODO
        // local.sin_addr.s_addr = INADDR_ANY;

        // 2.2 bind ： 设置进入内核中
        int n = ::bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success";
    }
    void RegisterService(adduser_t adduser, route_t route, remove_t removeuser)
    {
        _adduser = adduser;
        _route = route;
        _removeuser = removeuser;
    }
    void Start()
    {
        _isrunning = true;
        while (true)
        {
            char inbuffer[1024]; // string
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer); // 必须设定

            ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
            if (n > 0)
            {
                // 1. 消息内容 && 2. 谁发给我的
                // uint16_t clientport = ::ntohs(peer.sin_port);
                // std::string clientip = ::inet_ntoa(peer.sin_addr);

                InetAddr cli(peer);
                inbuffer[n] = 0;
                std::string message;
                if (strcmp(inbuffer, "QUIT") == 0)
                {
                    // 移除观察者
                    _removeuser(cli);
                    message = cli.Addr() + "# " + "Quitted!";
                }
                else
                {
                    // 2. 新增用户
                    _adduser(cli);
                    message = cli.Addr() + "# " + inbuffer;
                }

                // 3. 构建转发任务，推送给线程池，让线程池进行转发
                task_t task = std::bind(UdpServer::_route, _sockfd, message);
                ThreadPool<task_t>::getInstance()->Enqueue(task);

                // std::string clientinfo = cli.Ip() + ":" + std::to_string(cli.Port()) + " # " + inbuffer;

                // LOG(LogLevel::DEBUG) << clientinfo;

                // std::string echo_string = "echo# ";
                // echo_string += inbuffer;

                // ::sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, CONV(&peer), sizeof(peer));
            }
        }
        _isrunning = false;
    }
    ~UdpServer()
    {
        if (_sockfd > gsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;
    InetAddr _addr;
    bool _isrunning; // 服务器运行状态

    // 新增用户
    adduser_t _adduser;
    // 移除用户
    remove_t _removeuser;
    // 数据转发
    route_t _route;
};

#endif


// #ifndef __UDP_SERVER_HPP__
// #define __UDP_SERVER_HPP__


// #include <iostream>
// #include <string>
// #include <memory>
// #include <cstring>
// #include <cerrno>
// #include <strings.h>
// #include <functional>

// #include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>



// #include "Log.hpp"
// #include "InetAddr.hpp"
// #include "Common.hpp"
// #include "ThreadPool.hpp"

// using addUser_t = std::function<void(InetAddr &id)>;
// using delUser_t = std::function<void(InetAddr &id)>;

// using task_t = std::function<void()>;
// using route_t = std::function<void(int sockfd, const std::string & msg)>;

// using namespace ThreadPoolModule;
// using namespace LogModule;

// const static int gsockfd = -1;
// // const static std::string gdefaultip = "127.0.0.1"; // 表示本地主机
// const static uint16_t gdefaultport = 8888;

// class noCopy{
// public:
//     noCopy(){};
//     noCopy(const noCopy &) = delete;
//     noCopy operator = (noCopy ) = delete;
//     ~noCopy(){};
// };


// class UdpServer : public noCopy
// {
// public:
//     // 到时候 register adduser func  记得缺省参数放后面
//     UdpServer(addUser_t adduser , delUser_t deluser,route_t router, uint16_t port = gdefaultport)
//         : _sockfd(gsockfd)
//         , _addr(port)
//         , _isrunning(false)

//         , _adduser(adduser)
//         , _deluser(deluser)
//         , _router(router)
//     {
//     }
//     // 都是套路
//     void InitServer()
//     {
//         // 1. 创建socket
//         _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); // IP?PORT?网络？本地？
//         if (_sockfd < 0)
//         {
//             LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
//             Die(SOCK_ERR);
//         }
//         LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;
        
//         int n = ::bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());
//         if (n < 0)
//         {
//             LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
//             Die(BIND_ERR);
//         }
//         LOG(LogLevel::INFO) << "bind success";
//     }
//     void RegisterService(addUser_t adduser, route_t route, delUser_t removeuser)
//     {
//         _adduser = adduser;
//         _router = route;
//         _deluser = removeuser;
//     }

//     void Start()
//     {
//         _isrunning = true;
//         while (true)
//         {
//             char inbuffer[1024]; // string
//             struct sockaddr_in peer;
//             socklen_t len = sizeof(peer); // 必须设定

//             ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
//             if (n > 0)
//             {
//                 inbuffer[n] = 0;
//                 // 1. 消息内容 && 2. 谁发给我的(我是服务器哦)
//                 // uint16_t clientport = ::ntohs(peer.sin_port);
//                 // std::string clientip = ::inet_ntoa(peer.sin_addr);
//                 InetAddr cli(peer);
//                 // 如果用户输入QUIT会退出，或者在客户端给信号SIGINT也会退出
//                 std::string msg;
//                 if(strcmp(inbuffer, "QUIT") == 0)
//                 {
//                     _deluser(cli);
//                     msg = cli.Addr() + "# "+ "我走了哈";
//                     // _router(_sockfd, quit_msg);
//                 }                
//                 else
//                 {
//                     _adduser(cli);
//                     // _router(_sockfd, add_msg);
//                     msg += cli.Addr() + "# " + inbuffer;
//                     // _router(_sockfd, msg_broadcast);
//                 }

//                 // 构建任务给线程池，让线程池进行转发
//                 task_t task = std::bind(_router, _sockfd, msg);
//                 ThreadPool<task_t>::getInstance()->Enqueue(task);
//             }
//         }
//         _isrunning = false;
//     }
//     ~UdpServer()
//     {
//         if(_sockfd > gsockfd)
//             ::close(_sockfd);
//     }

// private:
//     int _sockfd;
//     InetAddr _addr;
//     // uint16_t _port;  // 服务器未来的端口号
//     // // std::string _ip; // 服务器所对应的IP
//     bool _isrunning; // 服务器运行状态

//     // 任务
//     addUser_t _adduser;
//     delUser_t _deluser;

//     route_t _router;

//     // 线程池 // 非单例模式 Singleton pattern
//     // ThreadPool<task_t> _threads;

// };

// #endif




// // #ifndef __UDP_SERVER_HPP__
// // #define __UDP_SERVER_HPP__

// // #include <iostream>
// // #include <cstring>
// // #include <cerrno>
// // #include <strings.h>
// // #include <string>

// // #include <sys/types.h>
// // #include <sys/socket.h>

// // #include <netinet/in.h>
// // #include <arpa/inet.h>

// // #include "Log.hpp"
// // #include "Common.hpp"

// // const static int g_sockfd = -1;
// // // INADDR_LOOPBACK
// // // const static std::string g_defualtIp = "127.0.0.1"; // 表示本地主机 INADDR_LOOPBACK 回环地址
// // const static uint16_t g_defaultPort = 8888;
// // using namespace LogModule;


// // // class UdpServer
// // // {
// // // private:
// // // public:
// // //     UdpServer(/*const std::string &ip = g_defualtIp,*/ uint16_t port = g_defaultPort)
// // //         : _sockfd(g_sockfd)
// // //         // , _ip(ip)
// // //         , _port(port)
// // //         , _isrunning(false)
// // //     {
// // //     }
// // //     void InitServer()
// // //     {
// // //         // 创建socket文件描述符
// // //         _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
// // //         if (_sockfd < 0)
// // //         {
// // //             LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
// // //             Die(err::SOCK_ERR);
// // //         }
// // //         LOG(LogLevel::INFO) << "socket: " << _sockfd << " success!";
    
// // //         // 填充网络信息，并bind
// // //         struct sockaddr_in local;
// // //         // 清零
// // //         bzero((void*)&local, sizeof(local));
        
// // //         local.sin_family = AF_INET; // Address family Internet
// // //         local.sin_port = ::htons(_port);
// // //         // C语言的结构体不能整体赋值，只能将每个成员分别赋值
// // //         // local.sin_addr = ::inet_addr(_ip.c_str());
// // //         // local.sin_addr = {::inet_addr(_ip.c_str())};
// // //         //或者
// // //         // local.sin_addr.s_addr = {::inet_addr(_ip.c_str())};
// // //         local.sin_addr.s_addr = INADDR_ANY;

// // //         int n = ::bind(_sockfd, CONV(&local), sizeof(local));
// // //         if(n < 0)
// // //         {
// // //             LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
// // //             Die(err::BIND_ERR);
// // //         }
// // //         LOG(LogLevel::INFO) << "bind success";
// // //     }
// // // void Start()
// // // {
// // //     _isrunning = true;
// // //     while(true)
// // //     {
// // //         char inbuffer[1024]; // 存储接收到的数据
// // //         struct sockaddr_in peer; // 远端
// // //         socklen_t len = sizeof(peer); // 必须设定
// // //         printf("1\n");
// // //         ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
// // //         printf("2\n");
// // //         if(n > 0) // 读取成功
// // //         {
// // //             // 消息内容和来源
// // //             inbuffer[n] = 0;  // 确保字符串正确终止

// // //             uint16_t clientPort = ::ntohs(peer.sin_port);
// // //             std::string clientIp = ::inet_ntoa(peer.sin_addr);

// // //             std::string clientInfo = clientIp + ":" + std::to_string(clientPort) + "#" + inbuffer;
// // //             LOG(LogLevel::DEBUG) << clientInfo;

// // //             // 构建回显内容
// // //             std::string echo_string = "echo# "; 
// // //             echo_string += inbuffer;

// // //             // 发送回显消息，只发送接收到的数据的有效部分（n）
// // //             sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, CONV(&peer), sizeof(peer));
// // //         }
// // //     }
// // //     _isrunning = false;
// // // }

// // //     ~UdpServer() {}

// // // private:
// // //     int _sockfd;
// // //     uint16_t _port; //服务器端口号
// // //     // std::string _ip; // IP
// // //     bool _isrunning; // 服务区运行状态
// // // };

// // // #endif